﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI.ETL.Domain.Services
{
    public class MappingService
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="dtSerId"></param>
        /// <param name="dtSourceId"></param>
        /// <param name="tableName"></param>
        /// <param name="isRawDt">是不是原始数据表</param>
        /// <param name="columnMapping">columnid,dtcol-name,dtcol-type,dtcol-length,dtcol-null,</param>
        /// <param name="dataIdentity">columnid,columnid</param>
        /// <returns></returns>
        public ServiceResult Mapping2NewTable(string userId, Guid dtSerId, Guid dtSourceId,
            string tableName,
            string tableDescription,
            bool isRawDt,
            string columnMapping,
            string dataIdentity)
        {
            if (string.IsNullOrEmpty(tableName)
                || string.IsNullOrEmpty(columnMapping)
                || string.IsNullOrEmpty(dataIdentity))
            {
                return new ServiceResult(false, ErrorCode.COM_InvalidParameter, ErrorCode.String(ErrorCode.COM_InvalidParameter));
            }

            using (EtlDbContext dbContext = new EtlDbContext())
            {
                //EntityRepository<Entities.EDtSourceColumn> scRep = new EntityRepository<Entities.EDtSourceColumn>(dbContext);
                EntityRepository<Entities.EDtTable> tRep = new EntityRepository<Entities.EDtTable>(dbContext);
                EntityRepository<Entities.EDtTableColumn> tcRep = new EntityRepository<Entities.EDtTableColumn>(dbContext);
                EntityRepository<Entities.EDtSourceMapping> smRep = new EntityRepository<Entities.EDtSourceMapping>(dbContext);
                EntityRepository<Entities.EDtSourceColumnMapping> scmRep = new EntityRepository<Entities.EDtSourceColumnMapping>(dbContext);
                EntityRepository<Entities.EDtSourceDataIdentity> sdiRep = new EntityRepository<Entities.EDtSourceDataIdentity>(dbContext);

                // 判断数据表是否存在
                if(tRep.Count(p=>p.Name == tableName) > 0)
                {
                    return new ServiceResult(false, ErrorCode.DtTable_NameExist, ErrorCode.String(ErrorCode.DtTable_NameExist));
                }

                if(smRep.Count(p=>p.DtSerId == dtSerId && p.DtSourceId == dtSourceId) > 0)
                {
                    return new ServiceResult(false, ErrorCode.DtSource_HasMappinged, ErrorCode.String(ErrorCode.DtSource_HasMappinged));
                }

                DateTime now = DateTime.Now;

                #region create table
                string[] columnMappingSegments = columnMapping.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                if (columnMappingSegments.Length == 0)
                {
                    // has not dt columns
                    return new ServiceResult(false, ErrorCode.NoColumnMapping, ErrorCode.String(ErrorCode.NoColumnMapping));
                }
                else if (columnMappingSegments.Length % 5 != 0)
                {
                    return new ServiceResult(false, ErrorCode.InvalidColumnMapping, ErrorCode.String(ErrorCode.InvalidColumnMapping));
                }

                List<string> dtTableColNames = new List<string>();
                List<string> dtTableColTypes = new List<string>();
                List<string> dtTableColLength = new List<string>();
                List<bool> dtTableColNullable = new List<bool>();

                for (int index = 0; index < columnMappingSegments.Length; index += 5)
                {
                    dtTableColNames.Add(columnMappingSegments[index + 1]);
                    dtTableColTypes.Add(columnMappingSegments[index + 2]);
                    dtTableColLength.Add(columnMappingSegments[index + 3]);
                    dtTableColNullable.Add(Convert.ToBoolean(columnMappingSegments[index + 4]));
                }

                #endregion

                // create table
                Entities.EDtTable eDtTable = new Entities.EDtTable();
                eDtTable.Id = Guid.NewGuid();
                eDtTable.Name = tableName;
                eDtTable.Description = tableDescription;
                eDtTable.ActualName = string.Format("ETL_DT_{0}", tableName);
                eDtTable.CacheName = string.Format("ETL_DTC_{0}", tableName);
                eDtTable.Creator = userId;
                eDtTable.CreatedTime = now;
                eDtTable.IsRawDt = isRawDt;
                tRep.Create(eDtTable);

                // create source mapping
                Entities.EDtSourceMapping eSMapping = new Entities.EDtSourceMapping();
                eSMapping.DtSerId = dtSerId;
                eSMapping.DtSourceId = dtSourceId;
                eSMapping.DtTableId = eDtTable.Id;
                eSMapping.Creator = userId;
                eSMapping.CreatedTime = now;
                smRep.Create(eSMapping);

                for (int index = 0; index < columnMappingSegments.Length; index += 5)
                {
                    // create table column
                    Entities.EDtTableColumn eDtColumn = new Entities.EDtTableColumn();
                    eDtColumn.Id = Guid.NewGuid();
                    eDtColumn.Name = columnMappingSegments[index + 1];
                    eDtColumn.Type = columnMappingSegments[index + 2];
                    try
                    {
                        eDtColumn.Length = Convert.ToInt16(columnMappingSegments[index + 3]);
                    }
                    catch (Exception ex)
                    {
                        Logger.DebugToTag(Library.LogTAG, string.Format("table:{0},转换列映射的Lenght出错，不是有效的int类型的数据", tableName));
                        eDtColumn.Length = 0;
                    }
                    eDtColumn.Nullable = Convert.ToBoolean(columnMappingSegments[index + 4]);
                    eDtColumn.Creator = userId;
                    eDtColumn.CreatedTime = now;
                    eDtColumn.DtTableId = eDtTable.Id;
                    eDtColumn.PK = false;
                    eDtColumn.IsSYS = false;
                    eDtColumn.Index = index / 5;
                    tcRep.Create(eDtColumn);

                    // create column mapping
                    Entities.EDtSourceColumnMapping eSCMapping = new Entities.EDtSourceColumnMapping();
                    eSCMapping.DtSerId = dtSerId;
                    eSCMapping.DtSourceColumnId = new Guid(columnMappingSegments[index]);
                    eSCMapping.DtSourceId = dtSourceId;
                    eSCMapping.DtTableColumnId = eDtColumn.Id;
                    eSCMapping.DtTableId = eDtTable.Id;
                    eSCMapping.Creator = userId;
                    eSCMapping.CreatedTime = now;
                    scmRep.Create(eSCMapping);
                }

                #region create data identity
                string[] dataIdentitySegments = dataIdentity.Split(new char[] { ',' });
                for (int index = 0; index < dataIdentitySegments.Length; index++)
                {
                    Entities.EDtSourceDataIdentity sdi = new Entities.EDtSourceDataIdentity();
                    sdi.DtSerId = dtSerId;
                    sdi.DtSourceId = dtSourceId;
                    sdi.DtSourceColumnId = new Guid(dataIdentitySegments[index]);
                    sdi.DtTableId = eDtTable.Id;
                    sdi.Index = index;
                    sdi.Creator = userId;
                    sdi.CreatedTime = now;
                    sdiRep.Create(sdi);
                }
                #endregion

                if (CPPEI.ETL.Domain.Util.DtTableUtil.CreateRawDataTable(dbContext,
                    eDtTable.ActualName,
                    eDtTable.CacheName,
                    isRawDt,
                    dtTableColNames,
                    dtTableColTypes, 
                    dtTableColLength,
                    dtTableColNullable) == false)
                {
                    return new ServiceResult(false, ErrorCode.COM_DBError, ErrorCode.String(ErrorCode.COM_DBError));
                }

                try
                {
                    if (dbContext.SaveChanges() > 0)
                    {
                        return new ServiceResult(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError));
                    }
                    else
                    {
                        return new ServiceResult(false, ErrorCode.COM_DBError, ErrorCode.String(ErrorCode.COM_DBError));
                    }
                }
                catch (Exception ex)
                {
                    Logger.ErrorToTag(Library.LogTAG, string.Format("映射到新数据表出错,ex:{0}", ex));
                    return new ServiceResult(false, ErrorCode.COM_Exception, ErrorCode.String(ErrorCode.COM_Exception));
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="dtSerId"></param>
        /// <param name="dtSourceId"></param>
        /// <param name="dtTableId"></param>
        /// <param name="columnMappings">columnid,dt-columnid,columnid,dt-columnid</param>
        /// <param name="dataIdentity"></param>
        /// <returns></returns>
        public ServiceResult Mapping2ExistTable(string userId, Guid dtSerId, Guid dtSourceId,
            Guid dtTableId,
            string columnMappings,
            string dataIdentity)
        {
            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Entities.EDtSourceColumn> scRep = new EntityRepository<Entities.EDtSourceColumn>(dbContext);
                EntityRepository<Entities.EDtTable> tRep = new EntityRepository<Entities.EDtTable>(dbContext);
                EntityRepository<Entities.EDtTableColumn> tcRep = new EntityRepository<Entities.EDtTableColumn>(dbContext);
                EntityRepository<Entities.EDtSourceMapping> smRep = new EntityRepository<Entities.EDtSourceMapping>(dbContext);
                EntityRepository<Entities.EDtSourceColumnMapping> scmRep = new EntityRepository<Entities.EDtSourceColumnMapping>(dbContext);
                EntityRepository<Entities.EDtSourceDataIdentity> sdiRep = new EntityRepository<Entities.EDtSourceDataIdentity>(dbContext);

                DateTime now = DateTime.Now;

                string[] columnMappingSegments = columnMappings.Split(new char[] { ',' });

                // create source mapping
                Entities.EDtSourceMapping eSMapping = new Entities.EDtSourceMapping();
                eSMapping.DtSerId = dtSerId;
                eSMapping.DtSourceId = dtSourceId;
                eSMapping.DtTableId = dtTableId;
                eSMapping.Creator = userId;
                eSMapping.CreatedTime = now;
                smRep.Create(eSMapping);

                for (int index = 0; index < columnMappingSegments.Length; index += 2)
                {
                    // create column mapping
                    Entities.EDtSourceColumnMapping eSCMapping = new Entities.EDtSourceColumnMapping();
                    eSCMapping.DtSerId = dtSerId;
                    eSCMapping.DtSourceColumnId = new Guid(columnMappingSegments[index]);
                    eSCMapping.DtSourceId = dtSourceId;
                    eSCMapping.DtTableColumnId = new Guid(columnMappingSegments[index+1]);
                    eSCMapping.DtTableId = dtTableId;
                    eSCMapping.Creator = userId;
                    eSCMapping.CreatedTime = now;
                    scmRep.Create(eSCMapping);
                }

                // 删除数据源的已有的 data identity
                dbContext.Database.ExecuteSqlCommand("delete ETL_DtSourceDataIdentity where DtSourceId={0} and DtTableId={1}", dtSourceId, dtTableId);

                #region create data identity
                string[] dataIdentitySegments = dataIdentity.Split(new char[] { ',' });
                for (int index = 0; index < dataIdentitySegments.Length; index++)
                {
                    Entities.EDtSourceDataIdentity sdi = new Entities.EDtSourceDataIdentity();
                    sdi.DtSerId = dtSerId;
                    sdi.DtSourceId = dtSourceId;
                    sdi.DtSourceColumnId = new Guid(dataIdentitySegments[index]);
                    sdi.DtTableId = dtTableId;
                    sdi.Index = index;
                    sdi.Creator = userId;
                    sdi.CreatedTime = now;
                    sdiRep.Create(sdi);
                }
                #endregion

                if (dbContext.SaveChanges() > 0)
                {
                    return new ServiceResult(true, ErrorCode.COM_NoError, "");
                }
                else
                {
                    return new ServiceResult(false, ErrorCode.COM_DBError, "");
                }
            }
        }

        /// <summary>
        /// 获取未映射的数据表
        /// </summary>
        /// <returns></returns>
        public ListResult<Entities.EDtTable> GetUnmappedTables()
        {
            using(EtlDbContext dbContext = new EtlDbContext())
            {
                List<Entities.EDtTable> list = dbContext.Database.SqlQuery<Entities.EDtTable>("exec [ETL_SP_GetUnmappedDtTables]").ToList();

                return new ListResult<Entities.EDtTable>(true, ErrorCode.COM_NoError, "", list);
            }
        }

        /// <summary>
        /// 获取已经映射的数据表
        /// </summary>
        /// <returns></returns>
        public ListResult<Entities.EDtTable> GetMappedTables()
        {
            using (EtlDbContext dbContext = new EtlDbContext())
            {
                List<Entities.EDtTable> list = dbContext.Database.SqlQuery<Entities.EDtTable>("exec [ETL_SP_GetMappedDtTables]").ToList();

                return new ListResult<Entities.EDtTable>(true, ErrorCode.COM_NoError, "", list);
            }
        }
    }
}
